﻿using ProjScan.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace ProjScan.Submodules.Art_Assets_Check
{
    internal class ShaderUtility
    {
        public class SphereGeometry
        {
            private struct TriangleIndices
            {
                public int v1;

                public int v2;

                public int v3;

                public TriangleIndices(int v1, int v2, int v3)
                {
                    this.v1 = v1;
                    this.v2 = v2;
                    this.v3 = v3;
                }
            }

            private int _index;

            private Dictionary<int, int> _indexDictionary;

            private List<Vector3> _vertices = new List<Vector3>();

            private int AddVertex(Vector3 vector3_0)
            {
                float num = Mathf.Sqrt(vector3_0.x * vector3_0.x + vector3_0.y * vector3_0.y + vector3_0.z * vector3_0.z);
                _vertices.Add(new Vector3(vector3_0.x / num, vector3_0.y / num, vector3_0.z / num));
                return _index++;
            }

            private int GetMiddlePoint(int point1, int point2)
            {
                bool flag = point1 < point2;
                int num = flag ? point1 : point2;
                int num2 = flag ? point2 : point1;
                int key = (num << 16) + num2;
                if (_indexDictionary.TryGetValue(key, out int value))
                {
                    return value;
                }

                Vector3 vector = _vertices[point1];
                Vector3 vector2 = _vertices[point2];
                Vector3 vector3_ = new Vector3((vector.x + vector2.x) / 2f, (vector.y + vector2.y) / 2f, (vector.z + vector2.z) / 2f);
                int num3 = AddVertex(vector3_);
                _indexDictionary.Add(key, num3);
                return num3;
            }

            public List<Vector3> Create(int divisionLevel)
            {
                _indexDictionary = new Dictionary<int, int>();
                _index = 0;
                float num = (1f + Mathf.Sqrt(5f)) / 2f;
                AddVertex(new Vector3(-1f, num, 0f));
                AddVertex(new Vector3(1f, num, 0f));
                AddVertex(new Vector3(-1f, 0f - num, 0f));
                AddVertex(new Vector3(1f, 0f - num, 0f));
                AddVertex(new Vector3(0f, -1f, num));
                AddVertex(new Vector3(0f, 1f, num));
                AddVertex(new Vector3(0f, -1f, 0f - num));
                AddVertex(new Vector3(0f, 1f, 0f - num));
                AddVertex(new Vector3(num, 0f, -1f));
                AddVertex(new Vector3(num, 0f, 1f));
                AddVertex(new Vector3(0f - num, 0f, -1f));
                AddVertex(new Vector3(0f - num, 0f, 1f));
                List<TriangleIndices> list = new List<TriangleIndices>();
                list.Add(new TriangleIndices(0, 11, 5));
                list.Add(new TriangleIndices(0, 5, 1));
                list.Add(new TriangleIndices(0, 1, 7));
                list.Add(new TriangleIndices(0, 7, 10));
                list.Add(new TriangleIndices(0, 10, 11));
                list.Add(new TriangleIndices(1, 5, 9));
                list.Add(new TriangleIndices(5, 11, 4));
                list.Add(new TriangleIndices(11, 10, 2));
                list.Add(new TriangleIndices(10, 7, 6));
                list.Add(new TriangleIndices(7, 1, 8));
                list.Add(new TriangleIndices(3, 9, 4));
                list.Add(new TriangleIndices(3, 4, 2));
                list.Add(new TriangleIndices(3, 2, 6));
                list.Add(new TriangleIndices(3, 6, 8));
                list.Add(new TriangleIndices(3, 8, 9));
                list.Add(new TriangleIndices(4, 9, 5));
                list.Add(new TriangleIndices(2, 4, 11));
                list.Add(new TriangleIndices(6, 2, 10));
                list.Add(new TriangleIndices(8, 6, 7));
                list.Add(new TriangleIndices(9, 8, 1));
                for (int i = 0; i < divisionLevel; i++)
                {
                    List<TriangleIndices> list2 = new List<TriangleIndices>();
                    foreach (TriangleIndices item in list)
                    {
                        int middlePoint = GetMiddlePoint(item.v1, item.v2);
                        int middlePoint2 = GetMiddlePoint(item.v2, item.v3);
                        int middlePoint3 = GetMiddlePoint(item.v3, item.v1);
                        list2.Add(new TriangleIndices(item.v1, middlePoint, middlePoint3));
                        list2.Add(new TriangleIndices(item.v2, middlePoint2, middlePoint));
                        list2.Add(new TriangleIndices(item.v3, middlePoint3, middlePoint2));
                        list2.Add(new TriangleIndices(middlePoint, middlePoint2, middlePoint3));
                    }

                    list = list2;
                }

                return _vertices;
            }
        }

        private static string computePath;

        private static ComputeShader computeShader;

        public static int kernelK1Id = -1;

        public static int kernelK2Id = -1;

        public static int kernelK3Id = -1;

        public static int kernelK4Id = -1;

        public static List<List<Vector3>> vectors = new List<List<Vector3>>(4);

        public static void Initialize()
        {
            computePath = ToolsHelper.GetFullPathByName("ProjScanUtil.compute");
            FetchVectors(2);
        }

        public static void FetchTexture(string filePath, RenderTexture renderTexture)
        {
            RenderTexture active = RenderTexture.active;
            RenderTexture.active = renderTexture;
            Texture2D texture2D = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, mipChain: false);
            texture2D.ReadPixels(new Rect(0f, 0f, renderTexture.width, renderTexture.height), 0, 0);
            texture2D.Apply();
            RenderTexture.active = active;
            SaveTexture(filePath, texture2D);
        }

        public static List<Vector3> FetchVectors(int int_4)
        {
            if (vectors == null)
            {
                vectors = new List<List<Vector3>>(4);
            }

            if (vectors.Count > int_4 && vectors[int_4] == null)
            {
                vectors[int_4] = new SphereGeometry().Create(int_4);
            }
            else if (vectors.Count <= int_4)
            {
                for (int i = vectors.Count; i <= int_4; i++)
                {
                    SphereGeometry sphereGeometry = new SphereGeometry();
                    vectors.Add(sphereGeometry.Create(i));
                }
            }

            return vectors[int_4];
        }

        public static uint ManipulateVector(Vector2 vector2_0)
        {
            vector2_0.x = Mathf.Min(Mathf.Max(vector2_0.x * 65536f, 0f), 65536f);
            vector2_0.y = Mathf.Min(Mathf.Max(vector2_0.y * 65536f, 0f), 65535f);
            uint num = ConvertInputVector((uint)vector2_0.x);
            uint num2 = ConvertInputVector((uint)vector2_0.y);
            return num * 2 + num2;
        }

        public static uint ConvertInputVector(uint uint_0)
        {
            uint_0 &= 0xFFFF;
            uint_0 |= uint_0 << 8;
            uint_0 &= 0xFF00FF;
            uint_0 |= uint_0 << 4;
            uint_0 &= 0xF0F0F0F;
            uint_0 |= uint_0 << 2;
            uint_0 &= 0x33333333;
            uint_0 |= uint_0 << 1;
            uint_0 &= 0x55555555;
            return uint_0;
        }

        public static void SaveTexture(string path, Texture2D texture2D_0)
        {
            string path2 = path + ".png";
            byte[] bytes = texture2D_0.EncodeToPNG();
            File.WriteAllBytes(path2, bytes);
        }

        public static void CalculateAverageAndVariance(List<float> list, out float averageDensity, out float varianceOfDensity)
        {
            averageDensity = 0f;
            varianceOfDensity = 0f;
            foreach (float item in list)
            {
                averageDensity += item;
            }

            averageDensity /= list.Count;
            foreach (float item2 in list)
            {
                float num = item2 - averageDensity;
                varianceOfDensity += num * num;
            }

            varianceOfDensity /= list.Count;
        }

        public static RenderTexture RenderTextureFromMesh(Mesh inputMesh, int textureSize, string shaderName)
        {
            RenderTexture temporary = RenderTexture.GetTemporary(textureSize, textureSize, 32, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
            new Material(Shader.Find(shaderName)).SetPass(0);
            RenderTexture active = RenderTexture.active;
            RenderTexture.active = temporary;
            GL.PushMatrix();
            bool invertCulling = GL.invertCulling;
            GL.invertCulling = true;
            GL.Clear(clearDepth: true, clearColor: true, Color.black);
            Graphics.DrawMeshNow(inputMesh, Matrix4x4.identity);
            GL.PopMatrix();
            GL.invertCulling = invertCulling;
            RenderTexture.active = active;
            return temporary;
        }

        public static ComputeShader LoadComputeShader()
        {
            if (computeShader == null)
            {
                if (computePath == null)
                {
                    throw new Exception("MeshUtilComputePath is null");
                }

                computeShader = AssetDatabase.LoadAssetAtPath<ComputeShader>(computePath);
            }

            if (computeShader == null)
            {
                throw new Exception("Cannot find ProjScanUtil.compute");
            }

            return computeShader;
        }

        public static int FetchKernelK1()
        {
            if (kernelK1Id < 0)
            {
                kernelK1Id = LoadComputeShader().FindKernel("K1");
            }

            return kernelK1Id;
        }

        public static int FetchKernelK2()
        {
            if (kernelK2Id < 0)
            {
                kernelK2Id = LoadComputeShader().FindKernel("K2");
            }

            return kernelK2Id;
        }

        public static int FetchKernelK3()
        {
            if (kernelK3Id < 0)
            {
                kernelK3Id = LoadComputeShader().FindKernel("K3");
            }

            return kernelK3Id;
        }

        public static int FetchKernelK4()
        {
            if (kernelK4Id < 0)
            {
                kernelK4Id = LoadComputeShader().FindKernel("K4");
            }

            return kernelK4Id;
        }
    }
}